/*
 * @Author: Suo-Yuheng syh15399227325@163.com
 * @Date: 2025-09-10 22:31:36
 * @LastEditors: Suo-Yuheng syh15399227325@163.com
 * @LastEditTime: 2025-09-11 22:28:26
 * @FilePath: /0910/HttpServer.hpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#pragma once

#include <iostream>
#include <string>
#include <pthread.h>
#include <fstream>
#include <sys/types.h>
#include <sys/socket.h>
#include <vector>
#include <sstream>

#include "Socket.hpp"
#include "log.hpp"

static const int defaultport = 8888;

const std::string wwwroot = "./wwwroot"; // 可以用 读取 配置文件的方法，规定路径
const std::string homepage = "index.html";

const std::string sep = "\r\n";

class HttpServer;

struct ThreadData
{
public:
    ThreadData(int fd, HttpServer *ts)
        : sockfd(fd), httpsvr(ts)
    {
    }

    int sockfd;
    HttpServer *httpsvr;
};

class HttpRequest
{
public:
    void Deserialize(std::string req)
    {
        while (true)
        {
            // 把 http 请求报头 打散，按行 push 到 vector 中
            ssize_t pos = req.find(sep);
            if (pos == std::string::npos)
                break;
            std::string temp = req.substr(0, pos);

            if (temp.empty())
                break; // 读到 空行就break

            req_header.push_back(temp);

            req.erase(0, pos + sep.size()); // 移除 处理过的 行
        }

        // 从 vector 中 查找 content-Length 属性，并获取键值，以 获取请求正文的 大小
        // 但是这里简化一下，剩下的全交给正文
        req_text = req;
    }

    void Parse()
    {
        // 分割字符串
        std::stringstream s((req_header[0]));
        s >> method >> url >> http_version; // 顺序不能变，协议规定

        file_path = wwwroot;
        if(url == "/" || url == "index.html")   // ./wwwroot/index.html
        {
            file_path += "/";
            file_path += homepage;
        }
        else
        {
            file_path += url;
        }
    }

    void DebugPrint()
    {
        for (auto &line : req_header)
        {
            std::cout << "--------------------------------------" << std::endl;
            std::cout << line << std::endl;
        }

        std::cout << "method: " << method << std::endl;
        std::cout << "url: " << url << std::endl;
        std::cout << "http_version: " << http_version << std::endl;
        std::cout << "file_path: " << file_path << std::endl;

        std::cout << req_text << std::endl;
    }

public:
    std::vector<std::string> req_header;
    std::string req_text;

    // 解析 请求报头的内容
    std::string method;
    std::string url;
    std::string http_version;
    std::string file_path;
};

class HttpServer
{
public:
    HttpServer(uint16_t port = defaultport)
        : port_(port)
    {
    }

    bool Start()
    {
        listensock_.Socket();
        
        listensock_.Bind(port_);
        listensock_.Listen();
        while (true)
        {
            std::string clientip;
            uint16_t clientport;
            int sockfd = listensock_.Accept(&clientip, &clientport);
            if (sockfd < 0)
                continue;

            pthread_t tid;
            ThreadData *td = new ThreadData(sockfd, this);
            pthread_create(&tid, nullptr, ThreadRun, td);
        }
    }

    static std::string ReadHtmlContent(const std::string &htmlpath)
    {
        // 文件操作
        std::ifstream in(htmlpath); // 坑
        // std::ifstream in(htmlpath, std::ios::binary); // 坑
        if (!in.is_open())
            return "";

        // // 读取二进制
        // in.seekg(0, std::ios_base::end);
        // auto len = in.tellg();  // 拿到文件大小
        // in.seekg(0, std::ios_base::beg);
        
        // std::string content;
        // content.resize(len);    // 把缓冲区强制申请出来

        // in.read((char *)content.c_str(), content.size());   // 把文件内容 全部读到缓冲区里，返回

        std::string content;
        std::string line;
        while (std::getline(in, line))
        {
            content += line;
        }

        in.close();
        return content;
    }

    static void HandlerHttp(int sockfd, HttpServer *httpsvr)
    {
        char buffer[10240];
        // ssize_t n = read(, buffer, sizeof(buffer) - 1);
        ssize_t n = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
        if (n > 0)
        {
            buffer[n] = '\0';
            std::cout << buffer; // 假设读到了 一个 完整的 http 请求、、其实应该循环读取，避免 解析不正确的 请求

            HttpRequest req;
            req.Deserialize(buffer); // 对请求作 ”反序列化“，把 http 请求 按行 打散，存到 vector 中，方便获取 每个属性
            req.Parse();
            req.DebugPrint();


            // http 收到请求，手动  构建 返回响应，并 发送给 套接字、给用户
            // std::string text = ReadHtmlContent("wwwroot/index.html");
            std::string text;
            bool ok = true;
            text = ReadHtmlContent(req.file_path);  // 读取 请求的资源，作为响应的正文内容，如果读取失败呢
            if(text.empty())
            {
                ok = false;
                std::string err_html = wwwroot;
                err_html += "/";
                err_html += "err.html";
                text = ReadHtmlContent(err_html);      // 读取 请求资源 失败，返回 失败的页面
            }

            std::string response_line;
            if(ok)
                response_line = "HTTP/1.0 200 OK\r\n";  // 状态码 200
            else
                response_line = "HTTP/1.0 404 Not Found\r\n";  // 状态码 404
            
            std::string response_header = "Content-Lenth: ";
            response_header += std::to_string(text.size());
            response_header += "\r\n";
            std::string blank_line = "\r\n";

            std::string response = response_line;
            response += response_header;
            response += blank_line;
            response += text;

            send(sockfd, response.c_str(), response.size(), 0);
        }
        close(sockfd);
    }

    static void *ThreadRun(void *args)
    {
        ThreadData *td = static_cast<ThreadData *>(args);

        pthread_detach(pthread_self());

        HandlerHttp(td->sockfd, td->httpsvr);

        delete td;
        return nullptr;
    }

    ~HttpServer()
    {
    }

private:
    Sock listensock_;
    uint16_t port_;
};